﻿// PreloadHelper.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <Windows.h>
#include <iostream>
#include <Shlwapi.h>
#include "constants.h"
#pragma comment(lib, "shlwapi.lib")

namespace {


    DWORD PreloadProcess(const std::string& cmd, bool isShown = false)
    {
        STARTUPINFO si = { 0 };
        GetStartupInfo(&si);
        si.dwFlags |= STARTF_USESHOWWINDOW;
        si.wShowWindow = isShown ? SW_SHOW : SW_HIDE;
        PROCESS_INFORMATION pi = { 0 };
        if (!CreateProcess(nullptr, const_cast<LPSTR>(cmd.c_str()), nullptr, nullptr, TRUE, NULL, nullptr, nullptr, &si, &pi)) {
            return 0;
        }
        DWORD pid = pi.dwProcessId;
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        return pid;
    }

    int DoPreload(int argc, char** argv) {
        std::string pname = argv[ARG_IDX_PNAME];
        if (PNAME_TO_WINDOW_NAME.find(pname) == PNAME_TO_WINDOW_NAME.end()) {
            return 0;
        }

        if (argc < ARG_COUNT_OPERATION_PNAME_FILEPATH) {
            return 0;
        }
        std::string cmdline = argv[ARG_IDX_FILEPATH_OR_CMDLINE];
        return PreloadProcess(cmdline);
    }

    int DoAwaken(int argc, char** argv) {
        std::string pname = argv[ARG_IDX_PNAME];
        if (PNAME_TO_WINDOW_NAME.find(pname) == PNAME_TO_WINDOW_NAME.end()) {
            return ERROR_APP_NAME;
        }
        // find & show window
        HWND wnd = FindWindow(nullptr, PNAME_TO_WINDOW_NAME.find(pname)->second.c_str());
        if (wnd) {
            ShowWindow(wnd, SW_SHOW);
            SetForegroundWindow(wnd);
        }
        std::string filepath;
        if (argc == ARG_COUNT_OPERATION_PNAME_FILEPATH) {
            filepath = argv[ARG_IDX_FILEPATH_OR_CMDLINE];
            if (!PathFileExists(filepath.c_str())) {
                return FILE_NOT_FOUND;
            }
        }
        ShellExecute(nullptr, nullptr, pname.c_str(), filepath.c_str(), nullptr, SW_SHOW);
        return SUCCEED;
    }

}

int main(int argc, char** argv)
{
    if (argc <= ARG_COUNT_NO_EXTRA_ARGS || argc > ARG_COUNT_OPERATION_PNAME_FILEPATH) {
        return ERROR_ARG_COUNT;
    }
    std::string operation = argv[ARG_IDX_OPERATION];
    if (operation == OP_PRELOAD) {
        return DoPreload(argc, argv);
    }
    else if (operation == OP_AWAKEN) {
        return DoAwaken(argc, argv);
    }
    return UNKNOWN;
}
